//
//  LBWebViewModule.m
//  LBReact
//
//  Created by WuShiHai on 19/5/24.
//  Copyright (c) 2019 Lebbay. All rights reserved.
//

#import "LBWebViewModule.h"
#import <LBWebView/LBWebView.h>
#import <LBFoundation/LBFoundation.h>
#import <React/RCTUIManager.h>
#import "LBReactConfigurationHeader.h"

@interface LBRWebView : LBWebView

/**
 每次有新的请求，均会触发此回调，回调结构如下：
 onRequest({
    "url":"http:www.baidu.com",
    "shouldRequst": @(YES),
    "method": "getUserInfo",
    "parameter": "0",
 });
 */
@property (nonatomic, copy) RCTDirectEventBlock onRequest;

/**
 当js调用postMessage方法时候，会触发该回调，回调结构如下：
 onPostMessage({
    info:{},
    url:"http://www.baidu.com",
    callback:"back",
 });
 */
@property (nonatomic, copy) RCTDirectEventBlock onPostMessage;

/**
 当加载的时候，进度更新会调用该回调，回调结构如下：
 onProgressChanged({
    progress: 12,//1-100
 });
 */
@property (nonatomic, copy) RCTDirectEventBlock onProgressChanged;

/**
 页面加载完成后的回调，回调结构如下：
 onReceivedTitle({
    "title": "百度一下"
 });
 */
@property (nonatomic, copy) RCTDirectEventBlock onReceivedTitle;

/**
 页面开始请求时候的回调，回调结构如下：
 onPageStarted({
    "canGoBack": YES,
    "canGoForward": YES,
 });
 */
@property (nonatomic, copy) RCTDirectEventBlock onPageStarted;

/**
 页面加载完成时候的回调，回调结构如下：
 onPageFinished({
    "canGoBack": YES,
    "canGoForward": YES,
 });
 */
@property (nonatomic, copy) RCTDirectEventBlock onPageFinished;

/**
 页面加载失败的回调，回调结构如下：
 onPageFailed({
    "message": "",
 });
 */
@property (nonatomic, copy) RCTDirectEventBlock onPageFailed;

/**
 webView初始化的请求链接
 */
@property (nonatomic, copy) NSString *url;

@end

@implementation LBRWebView

- (instancetype)initWithFrame:(CGRect)frame delegate:(id<LBWebViewDelegate>)delegate {
    if (self = [super initWithFrame:frame delegate:delegate]) {
        [self addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];
    }
    return self;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    LBBlockSafeRun(self.onProgressChanged, @{@"progress": @((NSInteger)(self.estimatedProgress * 100))});
}

- (void)dealloc {
    [self removeObserver:self forKeyPath:@"estimatedProgress"];
}

@end

@interface LBWebViewModule ()<LBWebViewDelegate>


@end

@implementation LBWebViewModule

RCT_EXPORT_MODULE(LBWebView)

- (UIView *)view {
    LBRWebView *webView = [[LBRWebView alloc] initWithFrame:CGRectZero
                                                   delegate:self];
    return webView;
}

RCT_EXPORT_VIEW_PROPERTY(onRequest, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onPostMessage, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onProgressChanged, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onReceivedTitle, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onPageStarted, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onPageFinished, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onPageFailed, RCTDirectEventBlock)
RCT_CUSTOM_VIEW_PROPERTY(url, NSString, LBRWebView) {
    NSMutableURLRequest *request =[NSMutableURLRequest requestWithURL:[NSURL URLWithString:(NSString *)json] cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:60];
    [view loadRequest:request];
}
RCT_EXPORT_VIEW_PROPERTY(allowsBackForwardNavigationGestures, BOOL)
RCT_EXPORT_METHOD(reload:(nonnull NSNumber *)reactTag) {
    [self.bridge.uiManager addUIBlock:
     ^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, LBRWebView *> *viewRegistry) {
         
         LBRWebView *view = viewRegistry[reactTag];
         if (!view || ![view isKindOfClass:[LBRWebView class]]) {
             RCTLogError(@"Cannot find RCTScrollView with tag #%@", reactTag);
             return;
         }
         [view reload];
     }];
}
RCT_EXPORT_METHOD(goForward:(nonnull NSNumber *)reactTag) {
    [self.bridge.uiManager addUIBlock:
     ^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, LBRWebView *> *viewRegistry) {
         
         LBRWebView *view = viewRegistry[reactTag];
         if (!view || ![view isKindOfClass:[LBRWebView class]]) {
             RCTLogError(@"Cannot find RCTScrollView with tag #%@", reactTag);
             return;
         }
         [view goForward];
     }];
}
RCT_EXPORT_METHOD(goBack:(nonnull NSNumber *)reactTag) {
    [self.bridge.uiManager addUIBlock:
     ^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, LBRWebView *> *viewRegistry) {
         
         LBRWebView *view = viewRegistry[reactTag];
         if (!view || ![view isKindOfClass:[LBRWebView class]]) {
             RCTLogError(@"Cannot find RCTScrollView with tag #%@", reactTag);
             return;
         }
         [view goBack];
     }];
}
RCT_EXPORT_METHOD(injectJavaScript:(nonnull NSNumber *)reactTag script:(NSString *)script callback:(RCTResponseSenderBlock)callback) {
    [self.bridge.uiManager addUIBlock:
     ^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, LBRWebView *> *viewRegistry) {
         
         LBRWebView *view = viewRegistry[reactTag];
         if (!view || ![view isKindOfClass:[LBRWebView class]]) {
             RCTLogError(@"Cannot find LBWebView with tag #%@", reactTag);
             return;
         }
         [view evaluateJavaScript:script completionHandler:^(id _Nullable info, NSError * _Nullable error) {
             LBBlockSafeRun(callback, info?@[info]:@[]);
         }];
     }];
}


#pragma mark - LBWebViewDelegate
- (BOOL)LBWebView:(LBRWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request {
    NSString *urlString = request.URL.absoluteString;
    NSString *method = @"";
    NSString *parameter = @"";
    BOOL shouldRequest = YES;
    NSString *appScheme = LBBundleConfigureStringValue(LBReactServiceConfiguration, LBReactServiceAppSchemeName, @"lebbayapp");
    if ([urlString hasPrefix:[NSString stringWithFormat:@"%@://", appScheme]]) {
        method = request.URL.host;
        NSRange range = [urlString rangeOfString:method];
        if (range.length + range.location + 1 < urlString.length) {
            parameter = [urlString substringFromIndex:range.location + range.length + 1];
            parameter = [parameter stringByRemovingPercentEncoding];
        }
        shouldRequest = NO;
    }
    //打开App Store
    if ([request.URL.host isEqualToString:@"itunes.apple.com"] && [request.URL.pathComponents containsObject:@"app"]) {
        if ([[UIApplication sharedApplication] canOpenURL:request.URL]) {
            [[UIApplication sharedApplication] openURL:request.URL];
            shouldRequest = NO;
        }
    }
    LBBlockSafeRun(webView.onRequest, @{@"url": urlString?:@"", @"shouldRequst":@(shouldRequest), @"method": method, @"parameter":parameter});
    return shouldRequest;
}
- (void)LBWebView:(LBRWebView *)webView didReceiveMessage:(LBWebViewBridge *)message {
    LBBlockSafeRun(webView.onPostMessage, [message yy_modelToJSON]);
}
- (void)LBWebViewDidStartLoad:(LBRWebView *)webView {
    NSDictionary *body = @{
                           @"canGoBack": @(webView.canGoBack),
                           @"canGoForward": @(webView.canGoForward),
                           };
    LBBlockSafeRun(webView.onPageStarted, body);
}
- (void)LBWebViewDidFinishLoad:(LBRWebView *)webView {
    NSDictionary *body = @{
                           @"canGoBack": @(webView.canGoBack),
                           @"canGoForward": @(webView.canGoForward),
                           @"url": webView.URL.absoluteString?:@"",
                           };
    LBBlockSafeRun(webView.onPageFinished, body);
    [webView evaluateJavaScript:@"document.title" completionHandler:^(id _Nullable info, NSError * _Nullable error) {
        if (info) {
            LBBlockSafeRun(webView.onReceivedTitle, @{@"title": info});
        }
    }];
}
- (void)LBWebView:(LBRWebView *)webView didFailLoadWithError:(NSError *)error {
    NSDictionary *body = @{
                           @"message": error.localizedDescription?:@"",
                           };
    LBBlockSafeRun(webView.onPageFailed, body);
}

@end
